package com.learn.base.aspect;

import cn.hutool.core.util.ArrayUtil;
import com.learn.base.annotation.ResubmitCheck;
import com.learn.base.enums.ResultCode;
import com.learn.base.exception.BusinessException;
import com.learn.base.utils.IpHelperUtil;
import com.learn.base.utils.JsonUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.time.Duration;
import java.util.Objects;

/**
 * @author : Yu.Tan
 * @date : 2023/2/8 14:24
 * @desc : **
 */
@Component
@Aspect
@Slf4j
public class ResubmitAspect {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Pointcut("@annotation(com.learn.base.annotation.ResubmitCheck)")
    public void aspect() {

    }

    @Before(value = "aspect()")
    public void exec(JoinPoint joinPoint) {


        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();

        String className = method.getDeclaringClass().getName();
        String methodName = method.getName();
        ResubmitCheck resubmitCheck = method.getAnnotation(ResubmitCheck.class);
        if (Objects.isNull(resubmitCheck)) {
            return;
        }
        //过期时间
        int expire = resubmitCheck.expire();

        //获取请求参数
        Object[] args = joinPoint.getArgs();
        if (ArrayUtil.isEmpty(args)) {
            return;
        }
        String params = JsonUtil.toJsonString(args);

        //获取请求IP
        String ipAddress = IpHelperUtil.getIpAddress();
        String resubmitCheckKey = ipAddress + ":" + className + methodName + params;
        log.info("check重复提交,key：{}", resubmitCheckKey);
        Boolean success = redisTemplate.opsForValue().setIfAbsent(resubmitCheckKey, "1", Duration.ofSeconds(expire));
        if (Objects.isNull(success) || !success) {
            throw new BusinessException(ResultCode.RATE_LIMIT_ERROR);
        }
    }
}
